import { createClient } from 'redis';
import { getServerEnv } from './env';
import serialize from 'serialize-javascript';
import logger from './logger';

function deserialize<T>(str: string): T {
  return eval('(' + str + ')');
}

const CLIENT = createClient({
  url: `redis://${getServerEnv('REDIS_HOST')}:${getServerEnv('REDIS_PORT')}`,
});

async function useClient() {
  if (!CLIENT.isReady) {
    await CLIENT.connect();
  }
  return CLIENT;
}

type CacheOptions<T> = {
  prefix: string;
  key: string;
  load: () => Promise<T | null>;
  ex: number;
};

export function withCache<T>({ prefix, key, load, ex }: CacheOptions<T>) {
  return async (): Promise<T | null> => {
    const client = await useClient();

    // TODO: 避免缓存击穿
    const cacheKey = `${prefix}:${key}`;
    const cachedValue = await client.get(cacheKey);
    if (cachedValue) {
      logger.info('cache hit', { key: cacheKey });
      return deserialize(cachedValue);
    } else {
      logger.info('cache not hit, try to load', { key: cacheKey });
    }

    const value = await load();
    if (value) {
      await client.set(cacheKey, serialize(value), { EX: ex });
      return value;
    } else {
      return null;
    }
  };
}

export async function clearCache(prefix: string, key: string) {
  const client = await useClient();
  const cacheKey = `${prefix}:${key}`;
  await client.del(cacheKey);
}
